using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;

namespace Net
{
    public class NetTcpServer
    {
        public TcpListener m_listen;
        public List<TcpClient> m_clients = new List<TcpClient>();
        //窗口显示数据事件
        public delegate void SendTargetData(DataType type, EndPoint point, object data);
        public event SendTargetData envSendTargetData;
        public NetTcpServer(int port)
        {
            m_listen = new TcpListener(IPAddress.Any, port);
            m_listen.Start();
            m_listen.BeginAcceptTcpClient(AcceptTcpClient, m_listen);
        }
        public void Recv<T>(TcpClient client, T data)
        {
            envSendTargetData?.Invoke(DataType.NetRecieve, client.Client.LocalEndPoint, data);
        }
        void AcceptTcpClient(IAsyncResult ar)
        {
            TcpClient recClient = m_listen.EndAcceptTcpClient(ar);
            try{
                lock(m_listen) m_clients.Add(recClient);
                envSendTargetData?.Invoke(DataType.NetConnected, recClient.Client.LocalEndPoint,null);
                m_listen.BeginAcceptTcpClient(AcceptTcpClient, m_listen);
                Task.Run(new Action(() =>
                {
                    ProtocolData recvProtocol = new ProtocolData(recClient, Recv);
                    recClient.Client.BeginReceive(recvProtocol.RecvBuf, 0, recvProtocol.RecvBuf.Length, 
                        SocketFlags.None, RecieveDataAsyn, new List<object>() { recClient, recvProtocol });
                }));
            }
            catch(Exception)
            {
                lock(m_listen) m_clients.Remove(recClient);
                m_listen.BeginAcceptTcpClient(AcceptTcpClient, m_listen);
            }
        }
        void RecieveDataAsyn(IAsyncResult res)
        {
            List<object> state = (List<object>)res.AsyncState;
            TcpClient recClient = (TcpClient)state[0];
            ProtocolData recvProtocol = (ProtocolData)state[1];
            try
            {
                recvProtocol.LeftByte += recClient.Client.EndReceive(res);
                if (!recClient.Connected ||(recClient.Client.Poll(1000, SelectMode.SelectRead) && (recClient.Available == 0)))
                {
                    lock(m_listen) m_clients.Remove(recClient);
                    envSendTargetData?.Invoke(DataType.NetClose,recClient.Client.LocalEndPoint, null);
                    return;
                }
                recvProtocol.RecvPackageData();
                int recvLength = recvProtocol.RecvBuf.Length - (recvProtocol.ProcessIndex + recvProtocol.LeftByte >= recvProtocol.RecvBuf.Length?
                    recvProtocol.LeftByte: (recvProtocol.ProcessIndex + recvProtocol.LeftByte));
                recClient.Client.BeginReceive(recvProtocol.RecvBuf, (recvProtocol.ProcessIndex+ recvProtocol.LeftByte)%recvProtocol.RecvBuf.Length,
                    recvLength, SocketFlags.None, RecieveDataAsyn, new List<object>() { recClient, recvProtocol });
            }
            catch (Exception)
            {
                if (!recClient.Connected || (recClient.Client.Poll(1000, SelectMode.SelectRead) && (recClient.Available == 0)))
                {
                    lock (m_listen) m_clients.Remove(recClient);
                    envSendTargetData?.Invoke(DataType.NetClose, recClient.Client.LocalEndPoint, null);
                }
                else
                {
                    envSendTargetData?.Invoke(DataType.LogInfo, recClient.Client.LocalEndPoint, "数据接收失败");
                }
            }
        }
        void SendDataAsyn(IAsyncResult res)
        {
            List<object> state = (List<object>)res.AsyncState;
            TcpClient sendClient = (TcpClient)state[0];
            byte[] sendData = (byte[])state[1];
            try
            {
                if (sendClient.Client.EndSend(res) != sendData.Length) 
                    envSendTargetData?.Invoke(DataType.LogInfo, sendClient.Client.LocalEndPoint, "数据发送失败");
            }
            catch (Exception)
            {
                envSendTargetData?.Invoke(DataType.LogInfo, sendClient.Client.LocalEndPoint, "数据发送失败");
            }
        }
        public void SendData(byte[] sendData)
        {
            lock (m_listen)
            {
                foreach (TcpClient sendClient in m_clients)
                {
                    try
                    {
                        if (sendClient.Client.Connected)
                            sendClient.Client.BeginSend(sendData, 0, sendData.Length, SocketFlags.None,
                                SendDataAsyn, new List<object> { sendClient, sendData });
                    }
                    catch (Exception)
                    {
                        envSendTargetData?.Invoke(DataType.LogInfo, sendClient.Client.LocalEndPoint, "数据发送失败");
                    }
                }
            }
        }
        public void SendData(TcpClient client,byte[] sendData)
        {
            lock (m_listen)
            {
                try
                {
                    if (client.Client.Connected)
                        client.Client.BeginSend(sendData, 0, sendData.Length, SocketFlags.None,
                            SendDataAsyn, new List<object> { client, sendData });
                }
                catch (Exception)
                {
                    envSendTargetData?.Invoke(DataType.LogInfo, client.Client.LocalEndPoint, "数据发送失败");
                }
            }
        }
    }
}
